/*
  Spimcp.cpp - customized SPI library for controlling the MCP4922 Analog to Digital Converter
*/


#include "SpiMCP4922.h"
#include <SPI.h>
//---------- constructor ----------------------------------------------------

SPIMCP::SPIMCP()
{
  // initialize the SPI pins
  pinMode(SCK_PIN, OUTPUT);
  pinMode(MOSI_PIN, OUTPUT);
  pinMode(MISO_PIN, INPUT);
  pinMode(SS1_PIN, OUTPUT);
  pinMode(SS2_PIN, OUTPUT);
  
  // Start with DAC CS pins to high (meaning not active)
  digitalWrite(SS1_PIN, HIGH);
  digitalWrite(SS2_PIN, HIGH);
  

  // enable SPI Master, MSB, SPI mode 0, FOSC/4
  mode(0);
}

void SPIMCP::init()
{
  // initialize the SPI pins
  pinMode(SCK_PIN, OUTPUT);
  pinMode(MOSI_PIN, OUTPUT);
  pinMode(MISO_PIN, INPUT);
  pinMode(SS1_PIN, OUTPUT);
  pinMode(SS2_PIN, OUTPUT);
  
  // Start with DAC CS pins to high (meaning not active). 
  // NOTE: IT IS THEREFORE IMPORANT TO CORRECTLY SET THE PORT VALUE when setting the CS to high or low, if we don't use a digitalWrite!!! 
  digitalWrite(SS1_PIN, HIGH);
  digitalWrite(SS2_PIN, HIGH);
  

  // enable SPI Master, MSB, SPI mode 0, FOSC/4
  mode(0);
}

//------------------ mode ---------------------------------------------------

void SPIMCP::mode(byte config)
{
  byte tmp;

  // enable SPI master with configuration byte specified
  SPCR = 0;
  SPCR = (config & 0x7F) | (1<<SPE) | (1<<MSTR);
  SPSR |= B00000001;
  tmp = SPSR;
  tmp = SPDR;
}

//------------------ transfer -----------------------------------------------

byte SPIMCP::transfer(byte value)
{
  SPDR = value;
  while (!(SPSR & (1<<SPIF))) ;
  return SPDR;
}

byte SPIMCP::transfer(byte value, byte period)
{
  SPDR = value;
  if (period > 0) delayMicroseconds(period);
  while (!(SPSR & (1<<SPIF))) ;
  return SPDR;
}


void SPIMCP::transfer16Bit(byte upperHalf, byte lowerHalf)
{
   // PORTC: 30 to 37  (PC0 is 37, PC6 is 30) 
  //digitalWrite(SS1_PIN, LOW);
  PORTC &= B11111110; // ENABLE FIRST DAC (mirrors) by putting pin 37 to LOW (this is, PORTC bit PC0) 
 
  
  SPDR = upperHalf;
  while (!(SPSR & (1<<SPIF))) ;
  
  SPDR = lowerHalf;
  while (!(SPSR & (1<<SPIF))) ;
  
  //digitalWrite(SS_PIN1, HIGH);
  PORTC |= B00000001;
}

//writeOutX and writeOutY create the right logical word to send to the Digital to Analog Converter (MCP4922) using the SPI16bit library.
//  MCP4922 WRITE COMMAND REGISTER:
//  bit15   14   13    12    11    10   ...   1    bit0
//   A/B   BUF   GA   SHDN   D11   D10  ...   D1   D0
//
//  bit15: '0'= write on A; '1'= write on B ("A"= mirror X; "B"= mirror Y)
//  bit14: '0'= unbuffered; '1'= buffered (I use "buffered")
//  bit13: '0'= 2x (VOUT = 2 * VREF * D/4096); '1'= 1x (VOUT = 2 * VREF * D/4096) (I use "gain 2x" because Vref=Vmax/2)
//  bit12: Output Power Down Control bit (here '1')


//write on the first DAC, output A (mirror X)
void SPIMCP::writeOutX(int value){
  //Set LOW on the Chip Select of the mirrors DAC
  PORTC &= B11111110; // ENABLE FIRST DAC (mirrors) by putting pin 37 to LOW (this is, PORTC bit PC0) 
  
  SPDR = (byte)(value >> 8) | B01010000 & B01011111;
  while (!(SPSR & (1<<SPIF))) ;
  
  SPDR = (byte)value;
  while (!(SPSR & (1<<SPIF))) ;
  
  //Set HIGH on the Chip Select of the mirrors DAC
  PORTC |= B00000001;
}

//write on the first DAC, output B (mirror Y)
void SPIMCP::writeOutY(int value){
  //Set LOW on the Chip Select of the mirrors DAC
  PORTC &= B11111110;
  
  SPDR = (byte)(value >> 8) | B11010000 & B11011111; 
  while (!(SPSR & (1<<SPIF))) ;
  
  SPDR = (byte)value;
  while (!(SPSR & (1<<SPIF))) ;
  
  //Set HIGH on the Chip Select of the mirrors DAC
  PORTC |= B00000001;
}

//write on the second DAC, output A (red Laser)
void SPIMCP::writeOutR(int value){
  //Set LOW on the Chip Select of the red laser DAC:
  PORTC &= B11111101;// ENABLE SECOND DAC (laser) by putting pin 36 to LOW (this is, PORTC bit PC1) 

 //creates 2 bytes containing the Highest part and the Lowest part of the 16-bits message
  byte MSBs = (byte)(value >> 8) | B01110000 & B01111111; //(byte)(value>>8) & B00001111 | B01110000;
  byte LSBs = (byte)(value);
  //send the Highest part first, then the lowest part
  SPI.transfer(MSBs);
  SPI.transfer(LSBs);

/* old code (HANGS!!!!) 
  SPDR = (byte)(value >> 8) | B01110000 & B01111111;
  while (!(SPSR & (1<<SPIF))) ;
  
  SPDR = (byte)value;
  while (!(SPSR & (1<<SPIF))) ;
 */
  
  //Set HIGH on the Chip Select of the laser DAC
  PORTC |= B00000010;
}


//---------- preinstantiate SPI object --------------------------------------

SPIMCP Spimcp = SPIMCP();
